<html>
<head><meta charset="utf-8"><title>Borrow Stack Races · t-lang/wg-unsafe-code-guidelines · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/index.html">t-lang/wg-unsafe-code-guidelines</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html">Borrow Stack Races</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="237846250"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/237846250" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#237846250">(May 07 2021 at 15:56)</a>:</h4>
<p>I was wondering how Stacked Borrows works arround race conditions involving the borrow stack. In particular, if an operation that pops a borrow item from the stack is potentially concurrent with an operation that uses that item, is it always undefined behaviour, or could it be defined (IE. the borrow stack has atomic relaxed or atomic unordered semantics). If the latter is the case, would a reborrow operation is considered an access (and in particular, a reborrow as Unique is considered a side effect) for the purposes of atomic ordering.</p>



<a name="237870438"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/237870438" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#237870438">(May 07 2021 at 18:36)</a>:</h4>
<p>If there is a race on the borrow stack, then that means that one possible interleaving has the pop happening before the use, in which case it is undefined behavior, and hence the entire execution is undefined behavior</p>



<a name="237870907"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/237870907" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#237870907">(May 07 2021 at 18:40)</a>:</h4>
<p>The only way this could be defined behavior is if there is something that prevents the race from occurring, and more specifically ensuring that the use <em>must</em> come before the pop. But the borrow stack itself cannot act as a synchronization mechanism because it has no associated hardware, so there is no point in giving it atomic access behavior</p>



<a name="237969347"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/237969347" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#237969347">(May 08 2021 at 16:49)</a>:</h4>
<p>Stacked Borrows is part of the operational semantics; all its effects happen atomically so the stack itself will never got "corrupted" or so</p>



<a name="237969402"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/237969402" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#237969402">(May 08 2021 at 16:50)</a>:</h4>
<p>but yeah you also can't use this to do synchronization, all weak memory / data race rules still apply</p>



<a name="238031100"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238031100" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238031100">(May 09 2021 at 11:59)</a>:</h4>
<p>Ok, so the answer is that it can be undefined behaviour at the implementation's discression (aka. it's undefined behaviour), then? <br>
Would the same applied to a reference this isn't subseuqently accessed, but is protected in other ways (such as by a protector). For example, would the following also be undefined behaviour guaranteed, or at the implementation's discression?</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">static</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">FOO</span>: <span class="kt">i32</span> <span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="c1">// static mut here to demonstraight racy creation of references</span>
<span class="k">static</span><span class="w"> </span><span class="n">COMPLETED</span>: <span class="nc">AtomicBool</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">AtomicBool</span>::<span class="n">new</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span><span class="w"></span>
<span class="c1">// This function runs on thread 1 with f = &amp;mut FOO</span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">thread1</span><span class="p">(</span><span class="n">f</span>: <span class="kp">&amp;</span><span class="nc">mut</span><span class="w"> </span><span class="kt">i32</span><span class="p">){</span><span class="w"></span>
<span class="w">    </span><span class="o">*</span><span class="n">f</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"></span>
<span class="w">     </span><span class="n">COMPLETED</span><span class="p">.</span><span class="n">store</span><span class="p">(</span><span class="kc">true</span><span class="p">,</span><span class="n">Ordering</span>::<span class="n">Release</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="c1">// This function runs on thread 2</span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">thread2</span><span class="p">(){</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="n">COMPLETED</span><span class="p">.</span><span class="n">load</span><span class="p">(</span><span class="n">Ordering</span>::<span class="n">Acquire</span><span class="p">){</span><span class="w"></span>
<span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">unsafe</span><span class="p">{</span><span class="w"> </span><span class="o">&amp;</span><span class="n">FOO</span><span class="w"> </span><span class="p">};</span><span class="w"></span>
<span class="w">        </span><span class="c1">// use f in some way</span>
<span class="w">   </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>



<a name="238031705"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238031705" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238031705">(May 09 2021 at 12:09)</a>:</h4>
<blockquote>
<p>Ok, so the answer is that it can be undefined behaviour at the implementation's discression (aka. it's undefined behaviour), then? </p>
</blockquote>
<p>Data races are already UB in Rust... Stacked Borrows doesnt change anything here.</p>



<a name="238031756"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238031756" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238031756">(May 09 2021 at 12:10)</a>:</h4>
<p>I dont know what you mean by "UB guaranteed" vs "at the implementation's discression"</p>



<a name="238031825"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238031825" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238031825">(May 09 2021 at 12:11)</a>:</h4>
<p>Your new example is interesting though. :)<br>
<code>thread1</code> takes a mutable reference that is guaranteed to be valid for the duration of this fn call, so indeed if there is another thread that invalidates that reference while <code>thread1</code> still runs, this is UB</p>



<a name="238031828"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238031828" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238031828">(May 09 2021 at 12:11)</a>:</h4>
<p>Really, it's a distinction without a difference, since the implementation would likely want to say it is, and even if it doesn't, it can do that for guaranteed UB. In any case, my question is more focused on these kinds of borrow-stack races when there isn't an underlying data race.</p>



<a name="238031867"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238031867" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238031867">(May 09 2021 at 12:12)</a>:</h4>
<p>and such an execution is possible in this program (there is UB in some non-deterministic branches and no UB in others)</p>



<a name="238031918"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238031918" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238031918">(May 09 2021 at 12:13)</a>:</h4>
<p>this is basically "the <code>Arc::drop</code> problem": <a href="https://github.com/rust-lang/rust/issues/55005">https://github.com/rust-lang/rust/issues/55005</a></p>



<a name="238032565"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238032565" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238032565">(May 09 2021 at 12:24)</a>:</h4>
<p>Indeed. My question is, can it be treated as always UB by the implementation unless there is some other form of explicit synchronization between the end of the call to <code>thread1</code>, and the start of the call to <code>thread2</code>?  <br>
That <code>Arc::drop</code> issue definately seems like a problem (though it's probably something that my implementation could solve, as I do, internally, have access to atomic operations on pointers).</p>



<a name="238040575"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238040575" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238040575">(May 09 2021 at 14:47)</a>:</h4>
<p>So is the emphasis on "always" in your question? Are you asking about how UB and scheduler non-determinism mix in general?</p>



<a name="238040767"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238040767" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238040767">(May 09 2021 at 14:51)</a>:</h4>
<p>This needs to be worked out carefully in more detail, but in general I'd say yes -- when only some interleavings have UB, the compiler can basically "pretend like that is the interleaving that happened" (as long as it does not do any other transformations that would make this interleaving impossible).</p>



<a name="238040780"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238040780" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238040780">(May 09 2021 at 14:51)</a>:</h4>
<p>This is the same as with regular "UB due to data races" (which, when formalized in the way I like formalizing it, also only leads to UB on <em>some</em> schedules)</p>



<a name="238050929"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238050929" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238050929">(May 09 2021 at 18:02)</a>:</h4>
<p><span class="user-mention silent" data-user-id="120791">RalfJ</span> <a href="#narrow/stream/136281-t-lang.2Fwg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races/near/238040575">said</a>:</p>
<blockquote>
<p>So is the emphasis on "always" in your question? Are you asking about how UB and scheduler non-determinism mix in general?</p>
</blockquote>
<p>Yes, or specifically, would making it "always" undefined behaviour be consistent with some superset of stacked borrows.<br>
I'm asking because in lccc (<a href="https://github.com/LightningCreaitons/lccc">https://github.com/LightningCreaitons/lccc</a>), I'm working on a different model that is of more general applicability, but it's intended to be a superset of stacked borrows (or whatever model rust may otherwise eventually adopt). In that model, the answer I would give is yes, owing to the "pointer-validity race" clause, which states (in part):</p>
<blockquote>
<p>If a derive expression (explicit or implicit) that invalidates a pointer  is <em>potentially concurrent</em> to an access through that pointer, or a derive expression (explicit or implicit) that requires validity of the pointer, the behaviour is undefined.</p>
</blockquote>
<p>Where "derive expression" is a generalization of reborrow, and invalidation is equivalent to "popping the borrow item" (protectors are implemented by inserting a <code>derive &lt;reference pointer type&gt;</code>, which in the case I showed, would cause a pointer-validity race and guaranteed undefined behaviour). Given the answer, I am satisfied that both the rule and the inserted derive are valid for an implementation.</p>



<a name="238055807"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238055807" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238055807">(May 09 2021 at 19:27)</a>:</h4>
<blockquote>
<p>Yes, or specifically, would making it "always" undefined behaviour be consistent with some superset of stacked borrows.</p>
</blockquote>
<p>In a purely operational model of concurrency and of UB, I dont know how to make it always UB. we'd need to add a bunch of extra machinery for that.<br>
but I think for all intents and purposes, there is not much difference between "UB on some schedules" and "UB on all schedules". (I wish I could give a more precise answer but I dont have a good enough formal grasp on this.)</p>



<a name="238056319"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238056319" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238056319">(May 09 2021 at 19:35)</a>:</h4>
<p>In nondeterministic models, isn't "UB on some schedules" just the same as UB overall? From the operational semantics POV they are different relations, but the compiler is permitted to assume there is no UB even on other schedules</p>



<a name="238056338"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238056338" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238056338">(May 09 2021 at 19:35)</a>:</h4>
<p>That's certainly how the C11 model works</p>



<a name="238056384"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238056384" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238056384">(May 09 2021 at 19:36)</a>:</h4>
<p>I don't really know how to define a "data race" without multiple schedules anyway</p>



<a name="238056519"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238056519" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238056519">(May 09 2021 at 19:38)</a>:</h4>
<p><span class="user-mention silent" data-user-id="120791">RalfJ</span> <a href="#narrow/stream/136281-t-lang.2Fwg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races/near/238040767">said</a>:</p>
<blockquote>
<p>This needs to be worked out carefully in more detail, but in general I'd say yes -- when only some interleavings have UB, the compiler can basically "pretend like that is the interleaving that happened" (as long as it does not do any other transformations that would make this interleaving impossible).</p>
</blockquote>
<p>I don't follow this part. If some interleavings have UB, then the compiler can do whatever it wants - it can remove or add UB operations all day long because the input program is broken</p>



<a name="238059786"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238059786" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238059786">(May 09 2021 at 20:35)</a>:</h4>
<p><span class="user-mention silent" data-user-id="120791">RalfJ</span> <a href="#narrow/stream/136281-t-lang.2Fwg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races/near/238055807">said</a>:</p>
<blockquote>
<blockquote>
<p>Yes, or specifically, would making it "always" undefined behaviour be consistent with some superset of stacked borrows.</p>
</blockquote>
<p>In a purely operational model of concurrency and of UB, I dont know how to make it always UB. we'd need to add a bunch of extra machinery for that.<br>
but I think for all intents and purposes, there is not much difference between "UB on some schedules" and "UB on all schedules". (I wish I could give a more precise answer but I dont have a good enough formal grasp on this.)</p>
</blockquote>
<p>I mean, presumably something based on the data race clause Rust inherented from C++ . It could be done by saying that pushing/directly removing <code>Unique</code> or a protector immediately above <code>Unique</code> is a side effect on all memory locations the <code>Unique</code> has access to, and pushing <code>SharedReadOnly</code> is a value computation (thus, any concurrent case that would conflict as above would be a data race). However, this cannot be done with <code>SharedReadWrite</code>, as it is valid to write to an <code>UnsafeCell</code> concurrently to borrowing it on another thread (atomics demonstrait this trivially), so it may be better to figure out a different solution.</p>



<a name="238140084"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238140084" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238140084">(May 10 2021 at 13:18)</a>:</h4>
<blockquote>
<p>I don't follow this part. If some interleavings have UB, then the compiler can do whatever it wants - it can remove or add UB operations all day long because the input program is broken</p>
</blockquote>
<p>I was worried about things that happen with other kinds of non-determinism...</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="n">x</span>: <span class="kt">bool</span> <span class="o">=</span><span class="w"> </span><span class="n">nondet_choice</span><span class="p">();</span><span class="w"></span>
<span class="fm">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">);</span><span class="w"></span>
<span class="kd">let</span><span class="w"> </span><span class="n">y</span>: <span class="kt">bool</span> <span class="o">=</span><span class="w"> </span><span class="n">read_from_stdin</span><span class="p">();</span><span class="w"></span>
<span class="k">if</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">cause_UB</span><span class="p">();</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>here, it is not okay for the program to first print <code>false</code> and later exploit UB. Even though there is UB on some executions, if we are demonstrably on a non-UB execution we cannot exploit that UB.</p>



<a name="238140539"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238140539" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238140539">(May 10 2021 at 13:21)</a>:</h4>
<p>I am less sure what happens if you remove the <code>read_from_stdin</code>...</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="n">x</span>: <span class="kt">bool</span> <span class="o">=</span><span class="w"> </span><span class="n">nondet_choice</span><span class="p">();</span><span class="w"></span>
<span class="fm">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">);</span><span class="w"></span>
<span class="k">if</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">cause_UB</span><span class="p">();</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>then there is UB on <em>all</em> branches under <code>x == true</code>... and such UB, at least in C, can travel "back in time", so we have UB already before the print, so the print is meaningless and <code>false</code> followed by anything is a correct execution: we could have picked <code>x := true</code>, then we have UB, and under UB we can print <code>false</code> and then do whatever.</p>



<a name="238140680"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238140680" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238140680">(May 10 2021 at 13:22)</a>:</h4>
<blockquote>
<p>I mean, presumably something based on the data race clause Rust inherented from C++</p>
</blockquote>
<p>Sure -- but the C++ model of data races is non-operational, which is very unsatisfying. That's why I specifically mentioned a "purely operational model of concurrency and of UB".</p>



<a name="238142200"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238142200" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238142200">(May 10 2021 at 13:32)</a>:</h4>
<p>Fair, though the reason I mentioned it is because its (effectively) what rust already has. For the point about non-determinisim leading to UB, I do agree. However, I suppose the next most important question would be, could the program observe any particular interleaving, given that actually accessing the data in a valid interleaving is still UB (since they would still be <em>potentially concurrent</em> <em>conflicting</em> accesses)?</p>



<a name="238151779"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238151779" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238151779">(May 10 2021 at 14:33)</a>:</h4>
<p>Indeed I agree that's a good question. ;)</p>



<a name="238151881"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238151881" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238151881">(May 10 2021 at 14:33)</a>:</h4>
<p>I think the answer is no and the compiler does not have to distinguish "UB in some interleavings" from "UB in all interleavings" for data races, but I don't know how to make this formal, let alone prove it.</p>



<a name="238155979"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238155979" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238155979">(May 10 2021 at 14:56)</a>:</h4>
<p>Actually, I wonder if there is a way to observe it using a combination of <code>AtomicPtr</code> and mutable references. </p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">static</span><span class="w"> </span><span class="n">ATOMIC_REF</span>: <span class="nc">AtomicPtr</span><span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">AtomicPtr</span>::<span class="n">new</span><span class="p">(</span><span class="n">core</span>::<span class="n">ptr</span>::<span class="n">null_mut</span><span class="p">());</span><span class="w"></span>

<span class="k">fn</span> <span class="nf">thread1</span><span class="p">(){</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">r</span>: <span class="kp">&amp;</span><span class="nc">mut</span><span class="w"> </span><span class="kt">i32</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Box</span>::<span class="n">leak</span><span class="p">(</span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="mi">5</span><span class="p">));</span><span class="w"></span>
<span class="w">    </span><span class="n">ATOMIC_REF</span><span class="p">.</span><span class="n">store</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="o">*</span><span class="n">r</span><span class="p">,</span><span class="n">Ordering</span>::<span class="n">Relaxed</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="k">fn</span> <span class="nf">thread2</span><span class="p">(){</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">r</span>: <span class="nb">Option</span><span class="o">&lt;&amp;</span><span class="k">mut</span><span class="w"> </span><span class="kt">i32</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">unsafe</span><span class="p">{</span><span class="n">ATOMIC_REF</span><span class="p">.</span><span class="n">load</span><span class="p">(</span><span class="n">Ordering</span>::<span class="n">Relaxed</span><span class="p">).</span><span class="n">as_mut</span><span class="p">()};</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>If it was guaranteed to be undefined behaviour, then it's undefined behaviour if <code>r</code> is given any value other than <code>None</code>, because the last-use of <code>r</code> in thread1 wouldn't be visible to the reborrow in thread2. However, I'm unsure if an interleaving exists such that the code is given defined behaviour, and if only such interleavings would have the store in thread1 be observed by the load in thread 2 (thus, the code always has defined behaviour).</p>



<a name="238239558"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238239558" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238239558">(May 11 2021 at 01:55)</a>:</h4>
<blockquote>
<p>If it was guaranteed to be undefined behaviour, then it's undefined behaviour</p>
</blockquote>
<p>I just realised that's a tautology. What I meant was if borrow stack races are guaranteed to be undefined behaviour, then producing <code>Some(_)</code> from those functions would be undefined behaviour.</p>



<a name="238262144"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238262144" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238262144">(May 11 2021 at 07:16)</a>:</h4>
<p>I would say this code is definitely <em>not</em> UB.</p>



<a name="238262173"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238262173" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238262173">(May 11 2021 at 07:17)</a>:</h4>
<p>oh wait, these are Relaxed accesses</p>



<a name="238262226"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238262226" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238262226">(May 11 2021 at 07:17)</a>:</h4>
<p>if <code>r</code> (when <code>Some</code>) is actually accessed, this is UB even without Stacked Borrows, right? that access would not be happens-after the allocation</p>



<a name="238262320"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238262320" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238262320">(May 11 2021 at 07:18)</a>:</h4>
<p>and even without Stacked Borrows there is an interesting question here, namely whether <code>dereferencable</code> (or the MIR equivalent) means that accesses are possible in a race-free way</p>



<a name="238262351"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238262351" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238262351">(May 11 2021 at 07:18)</a>:</h4>
<p>I think the answer to that is defnitely "no" since <code>&amp;UnsafeCell</code> is dereferencable</p>



<a name="238262367"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238262367" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238262367">(May 11 2021 at 07:19)</a>:</h4>
<p>so I assume this code actually has no UB</p>



<a name="238262397"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238262397" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238262397">(May 11 2021 at 07:19)</a>:</h4>
<p>but the interaction of weak memory and Stacked Borrows is entirely uncharted territory at the moment</p>



<a name="238283643"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238283643" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238283643">(May 11 2021 at 10:24)</a>:</h4>
<p>Indeed. The question is whether or not it's valid for the reborrow (which is the last-use) to be observed on thread2 after storing the resulting value on thread1, which is a variation on the ABA problem. If the borrow stack is made into an actual tracked mechanism by an implementation (IE. what miri does) with only Relaxed semantics, then it could be possible for that.<br>
If we used the following code instead, thread2 is permitted to observe r=1, s=1</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">static</span><span class="w"> </span><span class="n">X</span>: <span class="nc">AtomicI32</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">AtomicI32</span>::<span class="n">new</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span><span class="w"></span>
<span class="k">static</span><span class="w"> </span><span class="n">Y</span>: <span class="nc">AtomicI32</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">AtomicI32</span>::<span class="n">new</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="w"></span>

<span class="k">fn</span> <span class="nf">thread1</span><span class="p">(){</span><span class="w"></span>
<span class="w">    </span><span class="n">X</span><span class="p">.</span><span class="n">store</span><span class="p">(</span><span class="n">Y</span><span class="p">.</span><span class="n">fetch_add</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="n">Ordering</span>::<span class="n">Relaxed</span><span class="p">),</span><span class="n">Ordering</span>::<span class="n">Relaxed</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="k">fn</span> <span class="nf">thread2</span><span class="p">(){</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">X</span><span class="p">.</span><span class="n">load</span><span class="p">(</span><span class="n">Ordering</span>::<span class="n">Release</span><span class="p">);</span><span class="w"> </span><span class="c1">// this doesn't synchronize-with the store in thread1, but prevents the load below from being moved above here</span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Y</span><span class="p">.</span><span class="n">load</span><span class="p">(</span><span class="n">Ordering</span>::<span class="n">Relaxed</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>



<a name="238294129"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238294129" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238294129">(May 11 2021 at 11:58)</a>:</h4>
<blockquote>
<p>If the borrow stack is made into an actual tracked mechanism by an implementation (IE. what miri does)</p>
</blockquote>
<p>that's not what Miri does</p>



<a name="238294174"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238294174" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238294174">(May 11 2021 at 11:58)</a>:</h4>
<p>Miri implements the Abstract Machine directly, so that memory where it tracks Stacked Borrows is not visible to the program</p>



<a name="238294198"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238294198" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238294198">(May 11 2021 at 11:58)</a>:</h4>
<p>and not subject to any of the rules that "program memory" would be subject to</p>



<a name="238294296"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238294296" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238294296">(May 11 2021 at 11:59)</a>:</h4>
<p>when a write operation to location <code>l</code> changes the stack at <code>l</code> I think it is safe to say that those stack changes become visible together with the write to <code>l</code></p>



<a name="238294320"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238294320" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238294320">(May 11 2021 at 11:59)</a>:</h4>
<p>i.e., other threads observe the stack changes if and only if they see the value change</p>



<a name="238294366"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238294366" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238294366">(May 11 2021 at 12:00)</a>:</h4>
<p>but stacks can also change on read operations and then I dont think it is clear what the rules should be^^</p>



<a name="238309956"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238309956" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238309956">(May 11 2021 at 13:47)</a>:</h4>
<blockquote>
<blockquote>
<p>If the borrow stack is made into an actual tracked mechanism by an implementation (IE. what miri does)</p>
</blockquote>
<p>that's not what Miri does</p>
</blockquote>
<p>Fair, though is tracked in memory at runtime (just not the same memory as the program), so it could possibly run into the same issues (unless there are additional synchronization mechanisms, either on borrow stack pushes or on accesses to program memory).</p>



<a name="238313727"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238313727" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238313727">(May 11 2021 at 14:08)</a>:</h4>
<p><span class="user-mention silent" data-user-id="120791">RalfJ</span> <a href="#narrow/stream/136281-t-lang.2Fwg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races/near/238294296">said</a>:</p>
<blockquote>
<p>when a write operation to location <code>l</code> changes the stack at <code>l</code> I think it is safe to say that those stack changes become visible together with the write to <code>l</code></p>
</blockquote>
<p>The issues is that there isn't a write operation to some <code>l</code> that changes the stack that<code>r</code> is manipulating.  The borrow operation and the side effect are of unrelated memory locations (which the C++ memory models makes zero guarantess about without synchronization from release-acquire, or sequential-consistency, though release-consume could also be argued to apply as well).</p>



<a name="238320495"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238320495" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238320495">(May 11 2021 at 14:49)</a>:</h4>
<p>If we reason about the reborrow as a side-effect on some unspecified memory location <code>&amp;L</code>, then the potential ordering becomes apparent. On thread1, we have the following:</p>
<ul>
<li>atomic side-effect (or rmw) on &amp;L</li>
<li>
<p>atomic side-effect on M<br>
On thread2, the sequence-order is:</p>
</li>
<li>
<p>atomic value computation on M</p>
</li>
<li>(potentially) atomic side-effect (or rmw) on &amp;L.<br>
In this, it's possible for the side-effect on M from thread1 to become visible to thread2 before the value computation (thus the value computation reads the value the side effect stores), while not making the side-effect on &amp;L visible, allowing the reborrow in thread2 to appear earlier in the modification order of &amp;L, then the reborrow on thread1. I'm not sure of a way to reason about it, other than treating the borrow stack as an invisible memory location that is atomically modified with relaxed ordering.</li>
</ul>



<a name="238320797"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238320797" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238320797">(May 11 2021 at 14:51)</a>:</h4>
<p>Although, I did just realised I can't think of a reason that would be undefined behaviour. Even if that was the case (the reborrow in thread2 appeared earlier in the modification order of <code>&amp;L</code> then the reborrow on thread1), since neither are protected, it's not undefined behaviour unless one of them was subsequently used (specifically, in thread1, which would defeat the example).</p>



<a name="238321143"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238321143" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238321143">(May 11 2021 at 14:53)</a>:</h4>
<p>Actually, hm.. I assume you aren't allowed to reborrow from a borrow stack item that doesn't yet exist.</p>



<a name="238629329"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238629329" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238629329">(May 13 2021 at 14:33)</a>:</h4>
<blockquote>
<p>which the C++ memory models makes zero guarantess about without synchronization from release-acquire</p>
</blockquote>
<p>Not sure what you mean... release-acquire guarantes to make visible (after the acquire) all writes that happened-before the reads -- including to unrelated memory locations</p>



<a name="238629852"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238629852" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238629852">(May 13 2021 at 14:36)</a>:</h4>
<p>I'm saying that without release-acquire (or, sequential-consistency if all accesses were seq_cst), there aren't any guarantees about the ordering of accesses to independent memory locations. release-consume could probably also be argued to work (though rust doesn't have consume).</p>



<a name="238629953"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238629953" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238629953">(May 13 2021 at 14:37)</a>:</h4>
<p>(There should probably have been a comma before "without")</p>



<a name="238631102"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238631102" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238631102">(May 13 2021 at 14:45)</a>:</h4>
<p>oh, sorry, I misread</p>



<a name="238631190"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/238631190" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#238631190">(May 13 2021 at 14:46)</a>:</h4>
<p>yeah I prefer to ignore that consume even exists :P I'll wait until someone proposes a proper and precise spec for it...</p>



<a name="241152207"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow%20Stack%20Races/near/241152207" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races.html#241152207">(Jun 02 2021 at 13:56)</a>:</h4>
<p><span class="user-mention silent" data-user-id="271719">Mario Carneiro</span> <a href="#narrow/stream/136281-t-lang.2Fwg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races/near/238056519">said</a>:</p>
<blockquote>
<p><span class="user-mention silent" data-user-id="120791">RalfJ</span> <a href="#narrow/stream/136281-t-lang.2Fwg-unsafe-code-guidelines/topic/Borrow.20Stack.20Races/near/238040767">said</a>:</p>
<blockquote>
<p>This needs to be worked out carefully in more detail, but in general I'd say yes -- when only some interleavings have UB, the compiler can basically "pretend like that is the interleaving that happened" (as long as it does not do any other transformations that would make this interleaving impossible).</p>
</blockquote>
<p>I don't follow this part. If some interleavings have UB, then the compiler can do whatever it wants - it can remove or add UB operations all day long because the input program is broken</p>
</blockquote>
<p>Actually, yeah, having looked at the C++ section on the <em>as if</em> rule (particularily, the fact that UB applies if any execution has UB with the input). The compiler could choose a UB interleaving, but "pretend", at least partially, to be a valid interleaving (then <span aria-label="boom" class="emoji emoji-1f4a5" role="img" title="boom">:boom:</span>), because if the program execution path would lead to UB, it's no longer constrained to follow the <em>as-if</em> rule, so it could fake a valid path (including accidentally, because it assumed ~UB).</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>